Skip to content

This pull request introduces PostgreSQL database integration for product data management and retrieval in the NX AI FastAPI application. The main changes include adding scripts for database setup and testing, modifying the root API endpoint to return product data, and updating documentation and metadata for clarity.#7

Closed
goldlabelapps wants to merge 10 commits intomasterfrom
staging

Conversation

@goldlabelapps
Copy link
Copy Markdown
Owner

Database integration and management:

  • Added app/seed_product_table.py to create the product table and seed it with initial data in PostgreSQL.
  • Added app/print_products.py to print all products from the database for debugging and verification purposes.
  • Added app/test_db_connection.py to test database connectivity using environment variables.

API enhancements:

  • Modified the root endpoint in app/api/routes.py to connect to PostgreSQL, retrieve product data, and return it in the API response, including a count of products in the meta message.
  • Updated imports and setup in app/api/routes.py to support database connectivity and environment variable loading.

Documentation and metadata updates:

  • Updated README.md and app/main.py to clarify that the app is production-ready and to reflect the new database integration. [1] [2]
  • Bumped the version in app/__init__.py to 1.0.1 to reflect these changes.

@goldlabelapps goldlabelapps self-assigned this Mar 19, 2026
@goldlabelapps goldlabelapps requested a review from Copilot March 19, 2026 19:31
@github-project-automation github-project-automation Bot moved this to Backlog in Python Mar 19, 2026
@goldlabelapps goldlabelapps moved this from Backlog to In progress in Python Mar 19, 2026
@goldlabelapps goldlabelapps added this to the Upload CSV milestone Mar 19, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds PostgreSQL-backed product storage/retrieval to the NX AI FastAPI app, including scripts to initialize/inspect the database and updating the root endpoint to return product data.

Changes:

  • Added PostgreSQL utility scripts to test connectivity, create/seed the product table, and print product rows.
  • Updated GET / to query PostgreSQL and return product data with enriched meta.
  • Updated app metadata/docs and bumped package version.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
app/api/routes.py Root endpoint now loads env, connects to Postgres, queries product, and returns {meta, data}
app/main.py Updated FastAPI description string
app/init.py Bumped __version__ to 1.0.1
app/seed_product_table.py New script to create product table and insert seed data
app/print_products.py New script to print all rows from product
app/test_db_connection.py New script to test DB connectivity from env vars
README.md Minor wording tweak for “production-ready” description

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread app/main.py
Comment on lines 7 to 11
app = FastAPI(
title="NX AI",
description="A clean, modular FastAPI application for AI services.",
description="Production-ready Python FastAPI app for NX",
version="1.0.0",
)
Copy link

Copilot AI Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FastAPI(..., version="1.0.0") is now out of sync with app.__version__ (bumped to 1.0.1). Consider sourcing the FastAPI version from app.__version__ so API docs and metadata stay consistent.

Copilot uses AI. Check for mistakes.
Comment thread app/seed_product_table.py Outdated
Comment on lines +31 to +35
INSERT INTO product (name, description, price, in_stock) VALUES
('Widget', 'A useful widget', 19.99, TRUE),
('Gadget', 'A fancy gadget', 29.99, TRUE),
('Thingamajig', 'An interesting thingamajig', 9.99, FALSE)
ON CONFLICT DO NOTHING;
Copy link

Copilot AI Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ON CONFLICT DO NOTHING won't prevent duplicate seed rows here because the table has no unique constraint that these inserts can conflict on (the serial id isn't provided). Add a unique constraint (e.g., on name) and/or use an upsert target so re-running the script is idempotent.

Copilot uses AI. Check for mistakes.
Comment thread app/seed_product_table.py Outdated
Comment on lines +5 to +41
load_dotenv()

# Database connection
conn = psycopg2.connect(
host=os.getenv('DB_HOST'),
port=os.getenv('DB_PORT', '5432'),
dbname=os.getenv('DB_NAME'),
user=os.getenv('DB_USER'),
password=os.getenv('DB_PASSWORD')
)
cur = conn.cursor()

# Create product table
cur.execute('''
CREATE TABLE IF NOT EXISTS product (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
description TEXT,
price NUMERIC(10, 2) NOT NULL,
in_stock BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
''')

# Insert seed data
cur.execute('''
INSERT INTO product (name, description, price, in_stock) VALUES
('Widget', 'A useful widget', 19.99, TRUE),
('Gadget', 'A fancy gadget', 29.99, TRUE),
('Thingamajig', 'An interesting thingamajig', 9.99, FALSE)
ON CONFLICT DO NOTHING;
''')

conn.commit()
cur.close()
conn.close()
print("Product table created and seeded.")
Copy link

Copilot AI Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This script opens a DB connection at import time. Wrap the logic in a main() and guard it with if __name__ == "__main__": so importing the module doesn't create/seed tables unexpectedly (and so errors can be handled more cleanly).

Suggested change
load_dotenv()
# Database connection
conn = psycopg2.connect(
host=os.getenv('DB_HOST'),
port=os.getenv('DB_PORT', '5432'),
dbname=os.getenv('DB_NAME'),
user=os.getenv('DB_USER'),
password=os.getenv('DB_PASSWORD')
)
cur = conn.cursor()
# Create product table
cur.execute('''
CREATE TABLE IF NOT EXISTS product (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
description TEXT,
price NUMERIC(10, 2) NOT NULL,
in_stock BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
''')
# Insert seed data
cur.execute('''
INSERT INTO product (name, description, price, in_stock) VALUES
('Widget', 'A useful widget', 19.99, TRUE),
('Gadget', 'A fancy gadget', 29.99, TRUE),
('Thingamajig', 'An interesting thingamajig', 9.99, FALSE)
ON CONFLICT DO NOTHING;
''')
conn.commit()
cur.close()
conn.close()
print("Product table created and seeded.")
def main() -> None:
load_dotenv()
# Database connection
conn = psycopg2.connect(
host=os.getenv('DB_HOST'),
port=os.getenv('DB_PORT', '5432'),
dbname=os.getenv('DB_NAME'),
user=os.getenv('DB_USER'),
password=os.getenv('DB_PASSWORD')
)
cur = conn.cursor()
try:
# Create product table
cur.execute('''
CREATE TABLE IF NOT EXISTS product (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
description TEXT,
price NUMERIC(10, 2) NOT NULL,
in_stock BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
''')
# Insert seed data
cur.execute('''
INSERT INTO product (name, description, price, in_stock) VALUES
('Widget', 'A useful widget', 19.99, TRUE),
('Gadget', 'A fancy gadget', 29.99, TRUE),
('Thingamajig', 'An interesting thingamajig', 9.99, FALSE)
ON CONFLICT DO NOTHING;
''')
conn.commit()
print("Product table created and seeded.")
finally:
cur.close()
conn.close()
if __name__ == "__main__":
main()

Copilot uses AI. Check for mistakes.
Comment thread app/api/routes.py Outdated
Comment on lines 8 to 11
router = APIRouter()


router = APIRouter()
Copy link

Copilot AI Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

router = APIRouter() is declared twice; the first assignment is redundant and makes it easy to accidentally register routes on the wrong router instance. Keep a single router instance definition.

Copilot uses AI. Check for mistakes.
Comment thread app/api/routes.py
Comment on lines +5 to +7
import os
from dotenv import load_dotenv
import psycopg2
Copy link

Copilot AI Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This module now hard-depends on python-dotenv and psycopg2, but the repo's requirements.txt currently doesn't include them. Add the corresponding dependencies (e.g., python-dotenv and psycopg2-binary/psycopg2) so imports don't fail at runtime.

Copilot uses AI. Check for mistakes.
Comment thread app/api/routes.py Outdated
"id": row[0],
"name": row[1],
"description": row[2],
"price": float(row[3]),
Copy link

Copilot AI Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Casting NUMERIC to float can lose precision for prices. Prefer returning a Decimal-safe representation (e.g., str(row[3])) or use a serialization approach that preserves exact values.

Suggested change
"price": float(row[3]),
"price": str(row[3]) if row[3] is not None else None,

Copilot uses AI. Check for mistakes.
Comment thread app/api/routes.py
"message": f"NX AI says hello. Returned {len(products)} products."
}
return {"meta": meta}
return {"meta": meta, "data": products}
Copy link

Copilot AI Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The root response shape changed from the previous simple welcome message to {meta, data} and now depends on a live DB connection; the existing tests/test_routes.py::test_root_returns_welcome_message will fail (and CI may fail without a DB). Update tests and/or make DB access injectable/mockable so unit tests don't require external PostgreSQL.

Copilot uses AI. Check for mistakes.
Comment thread app/print_products.py Outdated
Comment on lines +5 to +23
load_dotenv()

conn = psycopg2.connect(
host=os.getenv('DB_HOST'),
port=os.getenv('DB_PORT', '5432'),
dbname=os.getenv('DB_NAME'),
user=os.getenv('DB_USER'),
password=os.getenv('DB_PASSWORD')
)
cur = conn.cursor()

cur.execute('SELECT * FROM product;')
rows = cur.fetchall()

for row in rows:
print(row)

cur.close()
conn.close()
Copy link

Copilot AI Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This script opens a DB connection at import time. Wrap the logic in a main() and guard it with if __name__ == "__main__": to avoid side effects if the module is imported (and to make error handling/exit codes cleaner).

Suggested change
load_dotenv()
conn = psycopg2.connect(
host=os.getenv('DB_HOST'),
port=os.getenv('DB_PORT', '5432'),
dbname=os.getenv('DB_NAME'),
user=os.getenv('DB_USER'),
password=os.getenv('DB_PASSWORD')
)
cur = conn.cursor()
cur.execute('SELECT * FROM product;')
rows = cur.fetchall()
for row in rows:
print(row)
cur.close()
conn.close()
def main():
load_dotenv()
conn = psycopg2.connect(
host=os.getenv('DB_HOST'),
port=os.getenv('DB_PORT', '5432'),
dbname=os.getenv('DB_NAME'),
user=os.getenv('DB_USER'),
password=os.getenv('DB_PASSWORD')
)
cur = conn.cursor()
cur.execute('SELECT * FROM product;')
rows = cur.fetchall()
for row in rows:
print(row)
cur.close()
conn.close()
if __name__ == "__main__":
main()

Copilot uses AI. Check for mistakes.
Comment thread app/test_db_connection.py Outdated
Comment on lines +5 to +33

# Load .env file
load_dotenv()

# Load environment variables
db_host = os.getenv('DB_HOST')
db_port = os.getenv('DB_PORT', '5432')
db_name = os.getenv('DB_NAME')
db_user = os.getenv('DB_USER')
db_password = os.getenv('DB_PASSWORD')

print("Attempting connection with:")
print(f"Host: {db_host}")
print(f"Port: {db_port}")
print(f"Database: {db_name}")
print(f"User: {db_user}")

try:
conn = psycopg2.connect(
host=db_host,
port=db_port,
dbname=db_name,
user=db_user,
password=db_password
)
print("Connection successful!")
conn.close()
except Exception as e:
print(f"Connection failed: {e}")
Copy link

Copilot AI Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This script executes connection attempts and prints connection details at import time. Wrap it in a main() with an if __name__ == "__main__": guard so importing the module doesn't trigger network access/printing (and so it can return a non-zero exit code on failure).

Suggested change
# Load .env file
load_dotenv()
# Load environment variables
db_host = os.getenv('DB_HOST')
db_port = os.getenv('DB_PORT', '5432')
db_name = os.getenv('DB_NAME')
db_user = os.getenv('DB_USER')
db_password = os.getenv('DB_PASSWORD')
print("Attempting connection with:")
print(f"Host: {db_host}")
print(f"Port: {db_port}")
print(f"Database: {db_name}")
print(f"User: {db_user}")
try:
conn = psycopg2.connect(
host=db_host,
port=db_port,
dbname=db_name,
user=db_user,
password=db_password
)
print("Connection successful!")
conn.close()
except Exception as e:
print(f"Connection failed: {e}")
import sys
def main() -> int:
# Load .env file
load_dotenv()
# Load environment variables
db_host = os.getenv('DB_HOST')
db_port = os.getenv('DB_PORT', '5432')
db_name = os.getenv('DB_NAME')
db_user = os.getenv('DB_USER')
db_password = os.getenv('DB_PASSWORD')
print("Attempting connection with:")
print(f"Host: {db_host}")
print(f"Port: {db_port}")
print(f"Database: {db_name}")
print(f"User: {db_user}")
try:
conn = psycopg2.connect(
host=db_host,
port=db_port,
dbname=db_name,
user=db_user,
password=db_password
)
print("Connection successful!")
conn.close()
return 0
except Exception as e:
print(f"Connection failed: {e}")
return 1
if __name__ == "__main__":
sys.exit(main())

Copilot uses AI. Check for mistakes.
Comment thread app/api/routes.py Outdated
Comment on lines +55 to +56
cur.close()
conn.close()
Copy link

Copilot AI Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cur.close()/conn.close() won't run if an exception occurs between connection creation and these lines, which can leak connections/cursors. Wrap DB operations in try/finally (or context managers) and return an appropriate error response when the query fails.

Copilot uses AI. Check for mistakes.
@goldlabelapps
Copy link
Copy Markdown
Owner Author

@copilot open a new pull request to apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 19, 2026

@goldlabelapps I've opened a new pull request, #8, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 5 commits March 19, 2026 19:40
…ing, main() guards, precision fix, tests

Co-authored-by: goldlabelapps <244006120+goldlabelapps@users.noreply.github.com>
Fix DB integration quality: dependency injection, idempotent seeding, price precision, and test isolation
@github-project-automation github-project-automation Bot moved this from In progress to Done in Python Mar 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants